package com.project.study.farming.base.service.impl;

import cn.hutool.core.util.StrUtil;
import com.project.study.farming.base.entity.dto.*;
import com.project.study.farming.base.entity.po.*;
import com.project.study.farming.base.manager.ConsumerManager;
import com.project.study.farming.base.service.MainPageService;
import com.project.study.farming.common.entity.dto.Page;
import com.project.study.farming.common.entity.po.UserPo;
import com.project.study.farming.common.exception.ServiceException;
import com.project.study.farming.common.mapper.BaseMapper;
import com.project.study.farming.common.utils.BeanMapper;
import com.project.study.farming.common.utils.CommonUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.ModelAndView;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 用户主页业务层实现类
 * @since 2020-04-25
 */
@Service
@Transactional
public class MainPageServiceImpl implements MainPageService {

    @Autowired
    private ConsumerManager consumerManager;

    @Autowired
    private BeanMapper beanMapper;

    @Autowired
    private BaseMapper baseMapper;

    @Override
    public ModelAndView initUser() {
        return CommonUtil.success("initUser.html", null);
    }

    @Override
    public ModelAndView searchMain(Integer pageNum) {
        List<MainPageDto> list = this.consumerManager.getMainPage();
        List<CropAreaPo> areas = this.beanMapper.selectList(CropAreaPo.class);
        List<AreaPo> areaPos = this.beanMapper.selectList(AreaPo.class, "is_delete = 103001");
        list.forEach(dto -> dto.setList(areas.stream().filter(area -> dto.getId().equals(area.getCropId())).map(area -> {
            CropAreaDto cropAreaDto = new CropAreaDto();
            BeanUtils.copyProperties(area, cropAreaDto);
            AreaPo apo = areaPos.stream().filter(ar -> ar.getId().equals(area.getAreaId())).findFirst().orElseThrow(() -> new ServiceException(String.format("植物%s土地信息异常！！！请管理员维护植物土地关系", dto.getName())));
            cropAreaDto.setAreaName(apo.getAreaName());
            return cropAreaDto;
        }).collect(Collectors.toList())));
        Map<String, Object> map = new HashMap<>(2);
        map.put("crops", Objects.isNull(pageNum) ? new Page<>(list) : new Page<>(pageNum, list));
        map.put("types", this.consumerManager.getTypes());
        return CommonUtil.success("about.html", map);
    }

    @Override
    public ModelAndView auditCrops(AuditCropsDto dto) {
        UserPo user = CommonUtil.getUser();
        Integer cropId = dto.getCropsId();
        Integer areaId = dto.getAreaId();
        AuditPo auditPo = this.beanMapper.selectOne(AuditPo.class, String.format("consumer_id = %s and crops_id = %s and area_id = %s and audit_status = 102001 and is_delete = 103001 and type = 105001", user.getId(), cropId, areaId));
        if(Objects.nonNull(auditPo)){
            auditPo.setCount(auditPo.getCount() + dto.getCount());
            this.beanMapper.updateById(auditPo);
        }else{
            auditPo = new AuditPo();
            BeanUtils.copyProperties(dto, auditPo);
            auditPo.setAreaId(areaId);
            auditPo.setAuditStatus(102001);
            auditPo.setIsDelete(103001);
            auditPo.setConsumerId(user.getId());
            auditPo.setCreateTime(LocalDateTime.now());
            auditPo.setCreateBy(user.getUsername());
            AreaPo areaPo = this.beanMapper.selectOne(AreaPo.class, String.format("id = %d", dto.getAreaId()));
            auditPo.setAuditName(areaPo.getAreaName());
            auditPo.setType(105001);
            this.beanMapper.insert(auditPo);
        }
        return this.searchMain(dto.getPageNum());
    }

    @Override
    public ModelAndView servicePage(Integer pageNum, Integer auditStatus, Integer cropId, Integer type) {
        Map<String, Object> map = new HashMap<>(8);
        List<ServicePageDto> list = this.consumerManager.servicePage(auditStatus, cropId, type);
        list.sort((i, j) -> {
            Integer si = i.getStatusValue(), sj = j.getStatusValue();
            if(si.equals(sj)){
                return i.getId() - j.getId();
            }else{
                return si - sj;
            }
        });
        if(Objects.isNull(type)){
            type = -1;
            map.put("types", new ArrayList<>());
        }
        map.put("audits",  Objects.isNull(pageNum) ? new Page<>(list) : new Page<>(pageNum, list));
        map.put("dic", this.baseMapper.getTcCode(102));
        map.put("cropMedi", this.baseMapper.getTcCode(105));
        if(105001 == type){
            map.put("types", this.beanMapper.selectList(CropsPo.class));
        }else if(105002 == type){
            List<MedicinePo> types = this.beanMapper.selectList(MedicinePo.class, "is_delete = 103001");
            map.put("types", types.stream().map(po -> {
                CropsPo cropsPo = new CropsPo();
                cropsPo.setId(po.getId());
                cropsPo.setName(po.getMedicineName());
                return cropsPo;
            }).collect(Collectors.toList()));
        }
        map.put("auditStatus", auditStatus);
        map.put("cropId", cropId);
        map.put("type", type);
        return CommonUtil.success("services.html", map);
    }

    @Override
    public ModelAndView messagePage(Integer pageNum) {
        List<MessagePo> list = this.beanMapper.selectList(MessagePo.class, "is_delete = 103001");
        List<MessageDto> res = new ArrayList<>();
        int userId = CommonUtil.getUser().getId();
        Supplier<MessageDto> sup = MessageDto :: new;
        list.stream().filter(po -> {
            boolean flag = !CommonUtil.getString(po.getReader()).contains(String.valueOf(userId));
            MessageDto dto = sup.get();
            BeanUtils.copyProperties(po, dto);
            if(flag){
                dto.setReadStatus("未读");
            }else{
                dto.setReadStatus("已读");
            }
            res.add(dto);
            return flag;
        }).forEach(po -> {
            String re = po.getReader();
            String reader = StrUtil.isBlank(re) ? String.format("%d", userId) : String.format("%s,%d", re, userId);
            po.setReader(reader);
            this.beanMapper.updateById(po);
        });
        res.sort((i, j) -> {
            String ri = i.getReadStatus(), rj = j.getReadStatus();
            if(ri.equals(rj)){
                long subId = i.getId() - j.getId();
                return subId > 0 ? 1 : subId < 0 ? -1 : 0;
            }else{
                return "未读".equals(ri) ? -1 : 1;
            }
        });
        return CommonUtil.successSelect("message.html", res, pageNum);
    }

    @Override
    public ModelAndView plantPage(Integer pageNum, Integer cropId, Integer plantStatus) {
        List<PlantPageDto> list = this.consumerManager.plantPage(CommonUtil.getUser().getId(), cropId, plantStatus);
        Map<String, Object> map = new HashMap<>(8);
        map.put("plantStatus", plantStatus);
        map.put("cropId", cropId);
        map.put("plants", Objects.isNull(pageNum) ? new Page<>(list) : new Page<>(pageNum, list));
        map.put("types",  this.beanMapper.selectList(CropsPo.class));
        map.put("dic", this.baseMapper.getTcCode(106));
        return CommonUtil.success("plant.html", map);
    }

    @Override
    public ModelAndView doPlant(Integer id, Integer pageNum) {
        UserPo user = CommonUtil.getUser();
        AuditPo auditPo = this.beanMapper.selectOne(AuditPo.class, String.format("id=%s", id));
        auditPo.setAuditStatus(102004);
        this.beanMapper.updateById(auditPo);
        PlantPo plantPo = new PlantPo();
        plantPo.setPlanter(user.getId());
        plantPo.setCreateBy(user.getUsername());
        plantPo.setCropsId(auditPo.getCropsId());
        plantPo.setAreaId(auditPo.getAreaId());
        plantPo.setThisSize(auditPo.getCount());
        plantPo.setCropsStatus(106001);
        plantPo.setId(null);
        plantPo.setPlanter(user.getId());
        plantPo.setCreateTime(LocalDateTime.now());
        plantPo.setCreateBy(user.getUsername());
        this.beanMapper.insert(plantPo);
        return this.servicePage(pageNum, null, null, null);
    }

    @Override
    public ModelAndView plantDetail(Integer id, Integer pageNum) {
        Map<String, Object> res = new HashMap<>(2);
        PlantDetailPo plantDetail = this.beanMapper.selectOne(PlantDetailPo.class, String.format("plant_id = %d and is_delete = 103001", id));
        if(Objects.isNull(plantDetail)){
            res.put("medicineName", StrUtil.EMPTY);
            plantDetail = new PlantDetailPo();
            plantDetail.setPlantId(id);
        }else{
            MedicinePo medicine = this.beanMapper.selectOne(MedicinePo.class, String.format("id = %d", plantDetail.getMedicineId()));
            String medicineName = Objects.isNull(medicine) ? StrUtil.EMPTY : medicine.getMedicineName();
            res.put("medicineName", medicineName);
        }
        res.put("detail", plantDetail);
        return CommonUtil.success("plantDetail.html", res);
    }

    @Override
    public ModelAndView savePlantDetail(PlantDetailPo detailPo) {
        UserPo user = CommonUtil.getUser();
        Integer id = detailPo.getId();
        LocalDateTime now = LocalDateTime.now();
        PlantDetailPo po;
        if(Objects.nonNull(id)){
            po = this.beanMapper.selectOne(PlantDetailPo.class, String.format("id = %d", id));
            po.setIsDelete(103002);
            this.beanMapper.updateById(po);
        }
        po = new PlantDetailPo();
        BeanUtils.copyProperties(detailPo, po);
        po.setIsDelete(103001);
        po.setCreateBy(user.getUsername());
        po.setCreateTime(now);
        this.beanMapper.insert(po);
        return this.plantPage(1, null, null);
    }

    @Override
    public ModelAndView controlPage(Integer pageNum, Integer cropId, Integer areaId) {
        Map<String, Object> res = new HashMap<>(8);
        List<ControlDto> list = this.consumerManager.controlPage(cropId, areaId);
        res.put("types", this.beanMapper.selectList(CropsPo.class));
        res.put("data", Objects.isNull(pageNum) ? new Page<>(list) : new Page<>(pageNum, list));
        res.put("areas", this.beanMapper.selectList(AreaPo.class, "is_delete = 103001"));
        res.put("cropId", cropId);
        res.put("areaId", areaId);
        return CommonUtil.success("control.html", res);
    }

    @Override
    public ModelAndView deleteControl(Integer id, Integer pageNum) {
        PlantDetailPo detail = this.beanMapper.selectOne(PlantDetailPo.class, String.format("plant_id = %d", id));
        detail.setIsDelete(103002);
        this.beanMapper.updateById(detail);
        return this.controlPage(1, null, null);
    }

    @Override
    public ModelAndView auditMedicine(Integer id) {
        Map<String, Object> res = new HashMap<>(2);
        List<MedicinePo> list = this.beanMapper.selectList(MedicinePo.class, "is_delete = 103001");
        res.put("id", id);
        res.put("data", list);
        return CommonUtil.success("auditMedicine.html", res);
    }

    @Override
    public ModelAndView saveAuditMedicine(AuditMedicineDto dto) {
        Integer plantId = dto.getPlantId(), medicine = dto.getMedicineId();
        double size = dto.getSize();
        UserPo user = CommonUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        PlantPo plant = this.beanMapper.selectOne(PlantPo.class, String.format("id = %d", plantId));
        AuditPo auditPo = new AuditPo();
        auditPo.setType(105002);
        auditPo.setCropsId(medicine);
        auditPo.setConsumerId(user.getId());
        auditPo.setAuditStatus(102001);
        auditPo.setAreaId(plant.getAreaId());
        auditPo.setIsDelete(103001);
        auditPo.setCount(size);
        MedicinePo medicineData = this.beanMapper.selectOne(MedicinePo.class, String.format("id = %d", medicine));
        auditPo.setAuditName(medicineData.getMedicineName());
        auditPo.setCreateTime(now);
        auditPo.setCreateBy(user.getUsername());
        Integer auditId = this.beanMapper.insert(auditPo);
        PlantDetailPo detail = this.beanMapper.selectOne(PlantDetailPo.class, String.format("plant_id = %d", plantId));
        detail.setAuditId(auditId);
        this.beanMapper.updateById(detail);
        return this.controlPage(1, null, null);
    }
}
